//
//  HomeTableViewController.swift
//  MyWeibo
//
//  Created by Roman on 15/9/6.
//  Copyright © 2015年 Roman. All rights reserved.
//

import UIKit

class HomeTableViewController: BaseTableViewController {
    
    /// 微博数据数组
    var statuses: [Status]? {
        didSet {
            // 刷新数据
            tableView.reloadData()
        }
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 如果用户没有登录, 设置访客视图, 返回
        if !UserAccount.userLogin {
            visitorView?.setupViewInfo(true, imageName: "visitordiscover_feed_image_smallicon", message: "关注一些人，回这里看看有什么惊喜")
            
            return
        }
        
        // 注册通知(注意:号)
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "selectPicture:", name: XJStatusCellSelectPictureNotification, object: nil)
        
        prepareTableView()
        loadData()
    }
    
    deinit {
        /// 注销通知
        NSNotificationCenter.defaultCenter().removeObserver(self)
    }
    
    ///  选中照片的监听方法
    ///
    ///  - param n: 通知对象
    @objc private func selectPicture(n: NSNotification) {

        // 获取参数 - 提示, 从'自定义'通知获取参数, 一定记住检查参数值!
        // urls
        guard let urls = n.userInfo![XJStatusCellSelectPictureURLKey] as? [NSURL] else {
            print("URL数组不存在")
            return
        }

        // indexPath
        guard let indexPath = n.userInfo![XJStatusCellSelectPictureIndexKey] as? NSIndexPath else {
            print("indexPath 不存在")
            return
        }
        
        // 检查图像视图
        guard let picView = n.object as? StatusPictureView else {
            print("图像视图不存在")
            return
        }
        
        // 记录属性
        pictureView = picView
        // 设置转场动画的 iconView
        presentIconView.sd_setImageWithURL(urls[indexPath.item])
        // 起始图片索引
        presentIndexPath = indexPath
        
        // 提示: 传递给照片查看器的照片索引, 只是一个整数! 适用面会更强!
        let vc = PhotoBrowserViewController(urls: urls, index: indexPath.item)
        
        // 自定义'转场' transitioning
        // 默认的转场完成之后, 之前的view会被移出屏幕
        // 1. 指定代理
        vc.transitioningDelegate = self
        // 2. 指定 Modal转场模式 - 自定义
        vc.modalPresentationStyle = UIModalPresentationStyle.Custom
        
        presentViewController(vc, animated: true, completion: nil)
    }
    
    /// 准备表格视图
    private func prepareTableView() {
        // 注册原型 cell
        // rawValue 返回枚举对应实际数值
        tableView.registerClass(StatusNormalCell.self, forCellReuseIdentifier: StatusCellIdentifier.NormalCell.rawValue)
        tableView.registerClass(StatusForwardCell.self, forCellReuseIdentifier: StatusCellIdentifier.ForwardCell.rawValue)
        // 设置表格的预估行高(方便表格提前计算预估行高, 提高性能) - 尽量准确, 能提高性能
        // 能够减少调用估算行高的次数
        tableView.estimatedRowHeight = 300
        
        // 设置表格自动计算行高
        // tableView.rowHeight = UITableViewAutomaticDimension
        
        // 如果不使用自动计算行高UITableViewAutomaticDimension, 不要使用底部约束
        // 提示: 很多bug是因为约束加多了, 捋清约束就好了
        // tableView.rowHeight = 300
        
        /// 取消分割线
        tableView.separatorStyle = UITableViewCellSeparatorStyle.None
        
        // 刷新控件 高度是60
        refreshControl = XJRefreshControl()
        // 添加监听方法
        refreshControl?.addTarget(self, action: "loadData", forControlEvents: UIControlEvents.ValueChanged)
    }
    
    /// 上拉刷新的标记
    private var pullupRefreshFlag = false
    
    /// 加载数据
    func loadData() {
        // 开始'下拉刷新' 动画 - 只是开启了刷新控件的动画, 并不会触发加载数据的方法
        refreshControl?.beginRefreshing()
        
        // 刷新新数据, 获取到数组中第一条记录的id
        // 第一次执行此方法的时候, statuses为空, since_id = 0, 加载最新的20条记录
        var since_id = statuses?.first?.id ?? 0
        
        // 判断是否是上拉刷新
        var max_id = 0
        if pullupRefreshFlag {
            since_id = 0
            
            // 记录数组最后一条记录的id
            max_id = statuses?.last?.id ?? 0
        }
        
        Status.loadStatus(since_id, max_id: max_id) { (dataList, error) -> () in
            
            // 关闭'下拉刷新'控件,  结束'下拉刷新' 动画
            self.refreshControl?.endRefreshing()
            // 复位上拉刷新标记, 保证下一次仍然能够上拉, 以及能够正确的执行下拉刷新
            self.pullupRefreshFlag = false
            
            if error != nil {
                print(error)
                return
            }
            
            let count = dataList?.count ?? 0
            print("刷新到\(count) 条数据")
            
            // 只有下拉刷新才需要提示
            if since_id > 0 {
                self.showPulldownTip(count)
            }
            
            // 如果没有数据, 直接返回
            if count == 0 {
                return
            }
            
            if since_id > 0 {       // 做下拉刷新, 应该将结果集合放在之前的微博数组前面
                self.statuses = dataList! + self.statuses!
            } else if max_id > 0 {      // 做上拉刷新, 应该将结果集合放在数组的后面
                self.statuses! += dataList!
            } else {
                self.statuses = dataList
            }
        }
    }
    
    /// 显示下拉刷新的数据条数
    private func showPulldownTip(count: Int) {
        
        // 提问: UIView 的动画是如何实现的? 是对核心动画的封装, 添加到控件的 layer 上
        // 快代码动画中, 修改frame 本质上是修改 position
        // 判断动画是否正在执行, 如果正在执行,
        print(tipLabel.layer.animationKeys())
        if tipLabel.layer.animationForKey("position") != nil {
            // 如果用户两次下拉间隔非常短, 通常是不会有新微博
            // 即便有新微博, 但是用户如此操作, 只给一次提示
            print("动画正在执行中...")
            return
        }
        
        // 定义标签文字
        tipLabel.text = (count == 0) ? "暂时没有新的微博" : "刷新到 \(count) 条微博"
        
        // 提示: 如果拖拽的比较快, 下一次动画的起点, 是上一次动画的目标终点, 造成提示栏不断向下
        print(tipLabel.frame)
        
        // 标签的初始位置
        let rect = tipLabel.frame
        
        UIView.animateWithDuration(2.0, animations: { () -> Void in
            
            // ‘7’ 的动画太快, 0.5s
//            UIView.setAnimationCurve(UIViewAnimationCurve(rawValue: 7)!)
            
            // 自动反转动画
            UIView.setAnimationRepeatAutoreverses(true)
            // 移动 label 的位置
            self.tipLabel.frame = CGRectOffset(rect, 0, 3 * rect.height)
            }) { (_) -> Void in
                // 将标签复位
                self.tipLabel.frame = rect
        }

        // 测试 curve 选项‘7’的动画时长
//        let anim = tipLabel.layer.animationForKey("position")
//        print("动画时长...\(anim?.duration)")
    }
    
    // MARK: - 数据源方法
    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return statuses?.count ?? 0
    }
    
    // 每次要显示 cell 的时候, 会调用此方法, 根据 indexPath判断数据方法
    // 如果 indexPath == 微博数组的总数-1, 表示要显示最后一行
    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        
        // 根据微博类型选取不同的Identifier
        let status = statuses![indexPath.row]
        
        let cell = tableView.dequeueReusableCellWithIdentifier(StatusCellIdentifier.cellId(status), forIndexPath: indexPath) as! StatusCell
        
        // 判断 indexPath 的数值
        if indexPath.row == statuses!.count - 1 {
            // 设置上拉刷新标记
            pullupRefreshFlag = true
            // 刷新数据
            loadData()
        }
        
        cell.status = statuses![indexPath.row]
        
        return cell
    }
    
    /// 返回行高 - 如果是固定值, 可以直接通过属性设置, 效率更高
    /**
    行高缓存
    1. NSCache - 内存缓存, iOS8.0模拟器有bug, 不能removeAll, 一旦removeAll之后再也没法使用
    真机没有这个问题, 在实际开发中, 一定以真机测试为准!
    SDWebImage 存在什么问题
    1>接收到内存警告后, 内存缓存失效
    2>加载GIF的时候, 内存会狂飙
    2. 自定义行高'缓存字典'
    
    3.直接利用微博的'模型' - 行高数据只是一个小数, 并不会有太大的内存消耗!
    不需要在控制器中额外定义属性
    
    提示: 如果表格高度是固定的, 一定不要通过代理返回行高! 直接设置属性值!
    3
    表格 & 数据源执行的顺序
    1.
    2.
    3.
    */
    override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
        
        // 判断模型中, 是否已经缓存了行高
        // 1. 获取模型
        let status = statuses![indexPath.row]
        
        if let h = status.rowHeight {
            return h
        }
        
        // 其它位置获取cell 的方法, 但是本函数中, 无法使用此方法获取到cell
        let c = tableView.cellForRowAtIndexPath(indexPath)
        
        // 2. 获取 cell - dequeueReusableCellWithIdentifier带 indexPath的函数会调用计算行高的方法
        // 会造成死循环, 在不同版本的xcode中 行高的计算次数不一样! 尽量要优化!
        // 如果不做处理, 会非常耗性能!
        let cell = tableView.dequeueReusableCellWithIdentifier(StatusCellIdentifier.cellId(status)) as? StatusCell
        
        // 3. 记录并返回计算的行高
        status.rowHeight = cell!.rowHeight(status)
        return status.rowHeight!
    }
    
    private lazy var tipLabel: UILabel = {
        let h: CGFloat = 44
        let label = UILabel(frame: CGRect(x: 0, y: -2 * h, width: self.view.bounds.width, height: h))
        
        label.backgroundColor = UIColor.orangeColor()
        label.textColor = UIColor.whiteColor()
        label.textAlignment = NSTextAlignment.Center
        
        // 将 label 添加到界面(view不合适, 会一起滚动)
        // view.addSubview(label)
        // 加载 navBar 上面, 不会随着 tableView 一起滚动
        self.navigationController?.navigationBar.insertSubview(label, atIndex: 0)
        
        return label
    }()
    
    /// 是否是 Modal 展现的标记
    private var isPresented = false
    /// 动画转场过程中的图像视图
    private lazy var presentIconView: UIImageView = {
        let iv = UIImageView()
        
        iv.contentMode = UIViewContentMode.ScaleAspectFill
        // 剪掉边框
        iv.clipsToBounds = true
        
        return iv
    }()
    /// 转场选中的图片的collectionView, 可以计算起始位置&目标位置
    private var pictureView: StatusPictureView?
    /// 转场起始的图片索引
    private var presentIndexPath: NSIndexPath?
}

/// 自定义转场的协议
extension HomeTableViewController: UIViewControllerTransitioningDelegate {
    
    /// 返回提供转场动画的遵守‘UIViewControllerContextTransitioning’协议的对象
    func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        isPresented = true
        
        return self
    }
    
    /// 返回提供解除转场的对象
    func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        
        isPresented = false
        
        return self
    }
}

/// MARK: - 自定义转场动画
extension HomeTableViewController: UIViewControllerAnimatedTransitioning {
    
    // 转场动画时长
    func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
        return 0.5
    }
    
    // 自定义转场动画 - 只要实现了此方法, 就需要自己来写动画代码
    /**
        transitionContext 提供了转场动画需要的元素
    
        completeTransition(true) 动画结束后必须调用
        containerView() 容器视图
    
        viewForKey      获取到转场的视图
    */
    func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
        
        // Modal
        if isPresented {
            
            // 最终要展现在界面上的 View，在动画结束之前不需要显示
            let toView = transitionContext.viewForKey(UITransitionContextToViewKey)!
            
            // 将动画的图像视图添加到目标视图中
            transitionContext.containerView()?.addSubview(presentIconView)
            // 指定图像视图的起始位置
            let fromRect = pictureView!.cellScreenFrame(presentIndexPath!)
            // 指定图像视图的目标位置
            let toRect = pictureView!.cellFulScreenFrame(presentIndexPath!)
            // 设置起始位置
            presentIconView.frame = fromRect
            
            UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
                
                // 动画运动到目标位置
                self.presentIconView.frame = toRect
                
                }) { (_) -> Void in
                    // 删除动画的图像视图
                    self.presentIconView.removeFromSuperview()
                    
                    // 添加目标视图
                    transitionContext.containerView()?.addSubview(toView)
                    
                    // 动画结束之后，一定要执行，如果不执行，系统会一直等待，无法进行后续的交互！
                    transitionContext.completeTransition(true)
            }

            return
        }
        
        // 解除转场
        // 照片查看器的控制器
        let fromVC = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) as! PhotoBrowserViewController
        // 从控制器获取当前显示的照片索引
        let indexPath = fromVC.currentImageIndex()
        // 获取到微博Cell 中collection cell对应的位置
        let rect = pictureView!.cellScreenFrame(indexPath)
        
        // 照片视图
        let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)!
        // 获取当前的图像视图
        let iv = fromVC.currentImageView()
        
        // 设置图像视图的位置
        iv.center = fromView.center
        // '累加'父视图的形变
        let scale = fromView.transform.a
        iv.transform = CGAffineTransformScale(iv.transform, scale, scale)
        
        // 将当前图像视图, 添加到容器视图
        transitionContext.containerView()?.addSubview(iv)
        
        // 将 fromView 从容器视图中移出
        fromView.removeFromSuperview()
        
        UIView.animateWithDuration(transitionDuration(transitionContext), animations: { () -> Void in
            
            // 修改目标位置
            iv.frame = rect
            
            }, completion: { (_) -> Void in
                 
                iv.removeFromSuperview()
                
                // 解除转场时, 会把 容器视图以及内部的内容一起销毁
                transitionContext.completeTransition(true)
        })
    }
}
 